// -*- mode:c++ -*-

// Copyright (c) 2009 The University of Edinburgh
// Copyright (c) 2021 IBM Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

////////////////////////////////////////////////////////////////////
//
// Integer ALU instructions
//

let {{

readXERCode = '[[maybe_unused]] Xer xer = XER;'

setXERCode = 'XER = xer;'

computeCR0Code = '''
{
    Cr cr = CR;
    Msr msr = MSR;
    cr.cr0 = msr.sf ?
             makeCRFieldSigned((int64_t)%(result)s, 0, xer.so) :
             makeCRFieldSigned((int32_t)%(result)s, 0, xer.so);
    CR = cr;
}
'''

computeCACode = '''
{
    Msr msr = MSR;
    if (findCarry(32, %(result)s, %(inputa)s, %(inputb)s)) {
        xer.ca = 1;
        xer.ca32 = 1;
    } else {
        xer.ca = 0;
        xer.ca32 = 0;
    }

    if (msr.sf) {
        if (findCarry(64, %(result)s, %(inputa)s, %(inputb)s)) {
            xer.ca = 1;
        } else {
            xer.ca = 0;
        }
    }
}
'''

computeOVCode = '''
{
    Msr msr = MSR;
    if (findOverflow(32, %(result)s, %(inputa)s, %(inputb)s)) {
        xer.ov = 1;
        xer.ov32 = 1;
    } else {
        xer.ov = 0;
        xer.ov32 = 0;
    }

    if (msr.sf) {
        if (findOverflow(64, %(result)s, %(inputa)s, %(inputb)s)) {
            xer.ov = 1;
        } else {
            xer.ov = 0;
        }
    }

    if (xer.ov) {
        xer.so = 1;
    }
}
'''

setCACode = '''
    if (setCA) {
        xer.ca = 1;
        xer.ca32 = 1;
    } else {
        xer.ca = 0;
        xer.ca32 = 0;
    }
'''

setOVCode = '''
    if (setOV) {
        xer.ov = 1;
        xer.ov32 = 1;
        xer.so = 1;
    } else {
        xer.ov = 0;
        xer.ov32 = 0;
    }
'''

}};


// A basic integer instruction.
def format IntOp(code, inst_flags = []) {{
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntOp', code, inst_flags, BasicDecode,
                 BasicConstructor)
}};


// Integer instructions with immediate (signed or unsigned).
def format IntImmOp(code, inst_flags = []) {{
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntImmOp', code, inst_flags, BasicDecode,
                 BasicConstructor)
}};


// Integer instructions with immediate that perform arithmetic.
// These instructions all write to Rt and use an altered form of the
// value in source register Ra, hence the use of src to hold the actual
// value. The control flags include the use of code to compute the
// carry bit or the CR0 code.
def format IntImmArithOp(code, computeCA = 0, computeCR0 = 0,
                         inst_flags = []) {{

    # Set up the dictionary
    dict = {'result':'Rt', 'inputa':'src', 'inputb':'si'}

    # Deal with computing CR0 and carry
    if computeCA or computeCR0:
        code += readXERCode
    if computeCA:
        code += computeCACode % dict + setXERCode
    if computeCR0:
        code += computeCR0Code % dict

    # Generate the class
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntImmArithOp', code, inst_flags, BasicDecode,
                 BasicConstructor)
}};


// Integer instructions with immediate that perform arithmetic but use
// the value 0 when Ra == 0. We generate two versions of each instruction
// corresponding to these two different scenarios. The correct version is
// determined at decode (see the CheckRaDecode template).
def format IntImmArithCheckRaOp(code, code_ra0, inst_flags = []) {{

    # First the version where Ra is non-zero
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntImmArithOp', code, inst_flags,
                 CheckRaDecode, BasicConstructor)

    # Now another version where Ra == 0
    (header_output_ra0, decoder_output_ra0, _, exec_output_ra0) = \
        GenAluOp(name, Name + 'RaZero', 'IntImmArithOp', code_ra0, inst_flags,
                 CheckRaDecode, BasicConstructor)

    # Finally, add to the other outputs
    header_output += header_output_ra0
    decoder_output += decoder_output_ra0
    exec_output += exec_output_ra0
}};


// Integer instructions with immediate that perform logic operations.
// All instructions write to Ra and use Rs as a source register. Some
// also compute the CR0 code too.
def format IntImmLogicOp(code, computeCR0 = 0, inst_flags = []) {{

    # Set up the dictionary and deal with computing CR0
    dict = {'result':'Ra'}

    # Code when Rc is set
    if computeCR0:
        code += readXERCode + computeCR0Code % dict

    # Generate the class
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntImmLogicOp', code, inst_flags, BasicDecode,
                 BasicConstructor)
}};


// Integer instructions with displacement that perform arithmetic.
// There are no control flags to set.
def format IntDispArithOp(code, inst_flags = []) {{

    # Generate the class
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntDispArithOp', code, inst_flags, BasicDecode,
                 BasicConstructor)
}};


// Integer compare instructions.
def format IntCompOp(code, inst_flags = []) {{

    # Add code to setup variables
    code = '[[maybe_unused]] uint32_t cr = 0;\n' + code
    code += 'CR = insertCRField(CR, bf, cr);\n'

    # Add code to access XER
    code = readXERCode + code

    # Generate the class
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntCompOp', code, inst_flags, BasicDecode,
                 BasicConstructor)
}};


// Integer immediate compare instructions.
def format IntImmCompOp(code, inst_flags = []) {{

    # Add code to setup variables
    code = '[[maybe_unused]] uint32_t cr = 0;\n' + code
    code += 'CR = insertCRField(CR, bf, cr);\n'

    # Add code to access XER
    code = readXERCode + code

    # Generate the class
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntImmCompOp', code, inst_flags, BasicDecode,
                 BasicConstructor)
}};


// Integer immediate compare logical instructions.
def format IntImmCompLogicOp(code, inst_flags = []) {{

    # Add code to setup variables
    code = '[[maybe_unused]] uint32_t cr = 0;\n' + code
    code += 'CR = insertCRField(CR, bf, cr);\n'

    # Add code to access XER
    code = readXERCode + code

    # Generate the class
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntImmCompLogicOp', code, inst_flags,
                 BasicDecode, BasicConstructor)
}};


// Integer instructions that perform logic operations. The result is
// always written into Ra. Some instructions have 2 versions depending on
// whether the Rc bit is set to compute the CR0 code. This is determined
// at decode as before.
def format IntLogicOp(code, computeCR0 = 0, inst_flags = []) {{
    dict = {'result':'Ra'}

    # Deal with computing CR0
    if computeCR0:
        # Setup the 2 code versions and add code to access XER if necessary
        code_rc1 = code + readXERCode + computeCR0Code % dict

        # Generate the first class
        (header_output, decoder_output, decode_block, exec_output) = \
            GenAluOp(name, Name, 'IntLogicOp', code, inst_flags,
                    CheckRcDecode, BasicConstructor)

        # Generate the second class
        (header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
            GenAluOp(name, Name + 'RcSet', 'IntLogicOp', code_rc1, inst_flags,
                    CheckRcDecode, BasicConstructor)

        # Finally, add to the other outputs
        header_output += header_output_rc1
        decoder_output += decoder_output_rc1
        exec_output += exec_output_rc1

    else:
        # Generate the class
        (header_output, decoder_output, decode_block, exec_output) = \
            GenAluOp(name, Name, 'IntLogicOp', code, inst_flags,
                     BasicDecode, BasicConstructor)
}};


// Integer instructions that perform shift operations. All of these
// instructions write to Ra and use Rs as a source register. The shift
// value is obtained from an register or an instruction field. If it
// from a register, Rb is also used as a source register. In certain
// situations, the carry bits have to be set and this is dealt with
// using the 'setCA' boolean in decoder.isa. We need two versions for
// each instruction to deal with the Rc bit.
def format IntShiftOp(code, computeCA = 0, inst_flags = []) {{
    dict = {'result':'Ra'}

    # Add code to setup variables and access XER if necessary
    code  = '[[maybe_unused]] bool setCA = false;\n' + code

    # Code when Rc is set
    code_rc1 = readXERCode + code + computeCR0Code % dict

    # Add code for calculating the carry, if needed
    if computeCA:
        code = readXERCode + code + setCACode + setXERCode
        code_rc1 += setCACode + setXERCode

    # Generate the first class
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntShiftOp', code, inst_flags,
                 CheckRcDecode, BasicConstructor)

    # Generate the second class
    (header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
        GenAluOp(name, Name + 'RcSet', 'IntShiftOp', code_rc1, inst_flags,
                 CheckRcDecode, BasicConstructor)

    # Finally, add to the other outputs
    header_output += header_output_rc1
    decoder_output += decoder_output_rc1
    exec_output += exec_output_rc1
}};


// Instructions in this format are all reduced to the form Rt = src1 + src2,
// therefore we just give src1 and src2 definitions. In working out the
// template we first put in the definitions of the variables and then
// the code for the addition. We also deal with computing the carry flag
// if required.
//
// We generate 4 versions of each instruction. This correspond to the
// different combinations of having the OE bit set or unset (which controls
// whether the overflow flag is computed) and the Rc bit set or unset too
// (which controls whether the CR0 code is computed).
def format IntSumOp(src1, src2, ca = {{ 0 }}, computeCA = 0,
                    inst_flags = []) {{

    # The result is always in Rt, but the source values vary
    dict = {'result':'Rt', 'inputa':'src1', 'inputb':'src2'}

    # Add code to set up variables and do the sum
    code  = 'uint64_t src1 = ' + src1 + ';\n'
    code += 'uint64_t src2 = ' + src2 + ';\n'
    code += 'uint64_t ca = ' + ca + ';\n'
    code += 'Rt = src1 + src2 + ca;\n'

    # Add code for calculating the carry, if needed
    if computeCA:
        code += computeCACode % dict + setXERCode

    # Setup the 4 code versions and add code to access XER if necessary
    code_rc1 = readXERCode + code
    code_oe1 = readXERCode + code + computeOVCode % dict + setXERCode
    code_rc1_oe1 = readXERCode + code + computeOVCode % dict + setXERCode
    if (computeCA or ca == 'xer.ca'):
        code = readXERCode + code
    code_rc1 += computeCR0Code % dict
    code_rc1_oe1 += computeCR0Code % dict

    # Generate the classes
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntArithOp', code, inst_flags,
                 CheckRcOeDecode, BasicConstructor)
    (header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
        GenAluOp(name, Name + 'RcSet', 'IntArithOp', code_rc1, inst_flags,
                 CheckRcOeDecode, BasicConstructor)
    (header_output_oe1, decoder_output_oe1, _, exec_output_oe1) = \
        GenAluOp(name, Name + 'OeSet', 'IntArithOp', code_oe1, inst_flags,
                 CheckRcOeDecode, BasicConstructor)
    (header_output_rc1_oe1, decoder_output_rc1_oe1, _, exec_output_rc1_oe1) = \
        GenAluOp(name, Name + 'RcSetOeSet', 'IntArithOp', code_rc1_oe1,
                 inst_flags, CheckRcOeDecode, BasicConstructor)

    # Finally, add to the other outputs
    header_output += \
        header_output_rc1 + header_output_oe1 + header_output_rc1_oe1
    decoder_output += \
        decoder_output_rc1 + decoder_output_oe1 + decoder_output_rc1_oe1
    exec_output += \
        exec_output_rc1 + exec_output_oe1 + exec_output_rc1_oe1

}};

// Instructions that use source registers Ra and Rb, with the result
// placed into Rt but do not check for carry, overflow or the Rc bit.
def format IntArithOp(code, inst_flags = []) {{

    # Generate the class
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntArithOp', code, inst_flags, BasicDecode,
                 BasicConstructor)
}};


// Instructions that use source registers Ra and Rb, with the result
// placed into Rt. Basically multiply and divide instructions. The
// carry bit is never set, but overflow can be calculated. In certain
// situations, the overflow bits have to be set and this is dealt with
// using the 'setOV' boolean in decoder.isa.
//
// In case overflow is to be calculated, we generate four versions of
// each instruction to deal with different combinations of having the
// OE bit set or unset and the Rc bit set or unset too. Otherwise, we
// generate two versions of each instruction to deal with the Rc bit.
def format IntArithCheckRcOp(code, computeOV = 0, inst_flags = []) {{

    # The result is always in Rt, but the source values vary
    dict = {'result':'Rt', 'inputa':'src1', 'inputb':'src2'}

    # Deal with setting the overflow flag
    if computeOV:
        # Setup the 4 code versions and add code to access XER if necessary
        code  = '[[maybe_unused]] bool setOV = false;\n' + code
        code_rc1 = readXERCode + code + computeCR0Code % dict
        code_oe1 = readXERCode + code + setOVCode + setXERCode
        code_rc1_oe1 = readXERCode + code + setOVCode + setXERCode
        code_rc1_oe1 += computeCR0Code % dict

        # Generate the classes
        (header_output, decoder_output, decode_block, exec_output) = \
            GenAluOp(name, Name, 'IntArithOp', code, inst_flags,
                     CheckRcOeDecode, BasicConstructor)
        (header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
            GenAluOp(name, Name + 'RcSet', 'IntArithOp', code_rc1, inst_flags,
                     CheckRcOeDecode, BasicConstructor)
        (header_output_oe1, decoder_output_oe1, _, exec_output_oe1) = \
            GenAluOp(name, Name + 'OeSet', 'IntArithOp', code_oe1, inst_flags,
                     CheckRcOeDecode, BasicConstructor)
        (header_output_rc1_oe1, decoder_output_rc1_oe1, _,
         exec_output_rc1_oe1) = \
            GenAluOp(name, Name + 'RcSetOeSet', 'IntArithOp', code_rc1_oe1,
                     inst_flags, CheckRcOeDecode, BasicConstructor)

        # Finally, add to the other outputs
        header_output += \
            header_output_rc1 + header_output_oe1 + header_output_rc1_oe1
        decoder_output += \
            decoder_output_rc1 + decoder_output_oe1 + decoder_output_rc1_oe1
        exec_output += \
            exec_output_rc1 + exec_output_oe1 + exec_output_rc1_oe1

    else:
        # Setup the 2 code versions and add code to access XER if necessary
        code_rc1 = readXERCode + code + computeCR0Code % dict

        # Generate the first class
        (header_output, decoder_output, decode_block, exec_output) = \
            GenAluOp(name, Name, 'IntArithOp', code, inst_flags,
                     CheckRcDecode, BasicConstructor)

        # Generate the second class
        (header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
            GenAluOp(name, Name + 'RcSet', 'IntArithOp', code_rc1, inst_flags,
                     CheckRcDecode, BasicConstructor)

        # Finally, add to the other outputs
        header_output += header_output_rc1
        decoder_output += decoder_output_rc1
        exec_output += exec_output_rc1
}};


// Integer instructions that also perform shift operations. Everything
// is same as above except if the shift value is not obtained from a
// register, two immediates need to be concatenated to get the final
// shift value.
def format IntConcatShiftOp(code, computeCA = 0, inst_flags = []) {{
    dict = {'result':'Ra'}

    # Add code to setup variables and access XER if necessary
    code  = '[[maybe_unused]] bool setCA = false;\n' + code

    # Code when Rc is set
    code_rc1 = readXERCode + code + computeCR0Code % dict

    # Add code for calculating the carry, if needed
    if computeCA:
        code = readXERCode + code + setCACode + setXERCode
        code_rc1 += setCACode + setXERCode

    # Generate the first class
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntConcatShiftOp', code, inst_flags,
                 CheckRcDecode, BasicConstructor)

    # Generate the second class
    (header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
        GenAluOp(name, Name + 'RcSet', 'IntConcatShiftOp', code_rc1,
                 inst_flags, CheckRcDecode, BasicConstructor)

    # Finally, add to the other outputs
    header_output += header_output_rc1
    decoder_output += decoder_output_rc1
    exec_output += exec_output_rc1
}};


// Integer instructions with or without immediate that perform rotate
// operations. All instructions write to Ra and use Rs as a source
// register. If immediate is not used, Rb is also used as a source
// register. We need two versions for each instruction to deal with
// the Rc bit.
def format IntRotateOp(code, inst_flags = []) {{

    # The result is always in Ra
    dict = {'result':'Ra'}

    # Code when Rc is set
    code_rc1 = readXERCode + code + computeCR0Code % dict

    # Generate the first class
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntRotateOp', code, inst_flags,
                 CheckRcDecode, BasicConstructor)

    # Generate the second class
    (header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
        GenAluOp(name, Name + 'RcSet', 'IntRotateOp', code_rc1, inst_flags,
                 CheckRcDecode, BasicConstructor)

    # Finally, add to the other outputs
    header_output += header_output_rc1
    decoder_output += decoder_output_rc1
    exec_output += exec_output_rc1
}};


// Everything is same as above except that the immediates may need to be
// concatenated to get the final values for the mask bounds or the shift
// value. We need two versions for each instruction to deal with the Rc
// bit.
def format IntConcatRotateOp(code, inst_flags = []) {{

    # The result is always in Ra
    dict = {'result':'Ra'}

    # Code when Rc is set
    code_rc1 = readXERCode + code + computeCR0Code % dict

    # Generate the first class
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntConcatRotateOp', code, inst_flags,
                 CheckRcDecode, BasicConstructor)

    # Generate the second class
    (header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
        GenAluOp(name, Name + 'RcSet', 'IntConcatRotateOp', code_rc1,
                 inst_flags, CheckRcDecode, BasicConstructor)

    # Finally, add to the other outputs
    header_output += header_output_rc1
    decoder_output += decoder_output_rc1
    exec_output += exec_output_rc1
}};


def format IntTrapOp(src1, src2, inst_flags = []) {{

    # Add code to set up variables and check for a trap
    code  = 'int64_t src1 = ' + src1 + ';\n'
    code += 'int64_t src2 = ' + src2 + ';\n'
    code += 'if (checkTrap(src1, src2)) {\n'
    code += '    return std::make_shared<TrapFault>();\n'
    code += '}\n'

    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntTrapOp', code, inst_flags, BasicDecode,
                 BasicConstructor)
}};


def format IntImmTrapOp(src, inst_flags = []) {{

    # Add code to set up variables and check for a trap
    code  = 'int64_t src = ' + src + ';\n'
    code += 'if (checkTrap(src, si)) {\n'
    code += '    return std::make_shared<TrapFault>();\n'
    code += '}\n'

    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntImmTrapOp', code, inst_flags, BasicDecode,
                 BasicConstructor)
}};
